#pragma once

#include <Channel.h>
// #include <EventLoop.h>
#include <Socket.h>
#include <Buffer.h>
#include <memory>

class Connection : public std::enable_shared_from_this<Connection>
{
    using TcpConnectionPtr = std::shared_ptr<Connection>;

    using MessageReadCallback = std::function<void(const TcpConnectionPtr &,Buffer::Buffer*)>;
    using CloseCallback = std::function<void(const TcpConnectionPtr &)>;
    using ConnectionCallback = std::function<void(const TcpConnectionPtr &)>;
    using WriteCompleteCallback = std::function<void(const TcpConnectionPtr &)>;
    using HighWaterMarkCallback = std::function<void(const TcpConnectionPtr &, size_t)>;

public:
    EventLoop *getLoop() { return loop_; }
    std::string name() { return name_; }

    bool connected() const { return state_ == kConnected; }
    bool disconnected() const { return state_ == kDisconnected; }

    Connection(EventLoop *loop, int fd, const std::string &name);
    void setMessageCallback(const MessageReadCallback &cb) { messageCallback_ = cb; }
    void setCloseCallback(const CloseCallback &cb) { closeCallback_ = cb; }
    void setWriteCompleteCallback(const WriteCompleteCallback &cb) { writeCompleteCallback_ = cb; }
    void setHighWaterMarkCallback(const HighWaterMarkCallback &cb) { highWaterMarkCallback_ = cb; }
    void setConnectionCallback(const ConnectionCallback &cb) { connectionCallback_ = cb; }

    // called when TcpServer accepts a new connection
    void connectEstablished(); // should be called only once

    // called when TcpServer has removed me from its map
    void connectDestroyed(); // should be called only once

    void send(const std::string &msg);

    void send(const char *msg, size_t len);

    void shutdown(); // NOT thread safe, no simultaneous calling

    void shutdownInLoop();

    ~Connection();

private:
    enum StateE
    {
        kDisconnected,
        kConnecting,
        kConnected,
        kDisconnecting
    };

    std::string stateToString();

    void setState(StateE s) { state_ = s; }

    void setTcpNoDelay(bool on);

    void handleRead();
    void handleWrite();
    void handleClose();
    void handleError();

    void startReadInLoop();

    void stopReadInLoop();

    void sendInLoop(const std::string &msg);

    /// @brief 向channel写长度为len的数据msg（函数有点复杂）
    /// @param msg
    /// @param len
    void sendInLoop(const char *msg, size_t len);

private:
    bool reading_;
    EventLoop *loop_;
    StateE state_;
    std::string name_;
    std::unique_ptr<Socket> socket_;
    std::unique_ptr<Channel> channel_;
    Buffer::Buffer inputBuffer_;
    Buffer::Buffer outputBuffer_;
    CloseCallback closeCallback_;
    ConnectionCallback connectionCallback_;
    MessageReadCallback messageCallback_;
    WriteCompleteCallback writeCompleteCallback_;
    size_t highWaterMark_;
    HighWaterMarkCallback highWaterMarkCallback_;
};
